package com.myzl.coal.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.myzl.coal.domain.Device;
import com.myzl.coal.domain.RowData;
import com.myzl.coal.mapper.DeviceMapper;
import com.myzl.coal.mapper.RowDataMapper;
import com.myzl.coal.mongo.component.MongoComponent;
import com.myzl.coal.mongo.domain.HistoryData;
import com.myzl.coal.service.IRowDataService;
import com.myzl.common.enums.DeviceCommandEnum;
import com.myzl.common.utils.DateUtils;
import com.myzl.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 每天每列统计Service业务层处理
 *
 * @author myzl
 * @date 2023-03-28
 */
@Service
public class RowDataServiceImpl extends ServiceImpl<RowDataMapper, RowData> implements IRowDataService
{
    @Autowired
    private RowDataMapper rowDataMapper;
    @Autowired
    private MongoComponent mongoComponent;
    @Autowired
    private DeviceMapper deviceMapper;

    /**
     * 查询每天每列统计
     *
     * @param id 每天每列统计主键
     * @return 每天每列统计
     */
    @Override
    public RowData selectRowDataById(Long id)
    {
        return rowDataMapper.selectRowDataById(id);
    }

    /**
     * 查询每天每列统计列表
     *
     * @param rowData 每天每列统计
     * @return 每天每列统计
     */
    @Override
    public List<RowData> selectRowDataList(RowData rowData)
    {
        return rowDataMapper.selectRowDataList(rowData);
    }

    /**
     * 新增每天每列统计
     *
     * @param rowData 每天每列统计
     * @return 结果
     */
    @Override
    public int insertRowData(RowData rowData)
    {
        rowData.setCreateTime(DateUtils.getNowDate());
        return rowDataMapper.insertRowData(rowData);
    }

    /**
     * 修改每天每列统计
     *
     * @param rowData 每天每列统计
     * @return 结果
     */
    @Override
    public int updateRowData(RowData rowData)
    {
        rowData.setUpdateTime(DateUtils.getNowDate());
        return rowDataMapper.updateRowData(rowData);
    }

    /**
     * 批量删除每天每列统计
     *
     * @param ids 需要删除的每天每列统计主键
     * @return 结果
     */
    @Override
    public int deleteRowDataByIds(Long[] ids)
    {
        return rowDataMapper.deleteRowDataByIds(ids);
    }

    /**
     * 删除每天每列统计信息
     *
     * @param id 每天每列统计主键
     * @return 结果
     */
    @Override
    public int deleteRowDataById(Long id)
    {
        return rowDataMapper.deleteRowDataById(id);
    }

    @Override
    public boolean everyDayRow(Integer deviceId,Integer standard) {
        Device device = deviceMapper.selectDeviceById(deviceId);
        List<RowData> rowDataList = new ArrayList<>();
        Integer count = rowDataMapper.selectCount(new LambdaUpdateWrapper<RowData>());
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(deviceId),
                Criteria.where("dictValue").is(DeviceCommandEnum.CURRENT_FLOW.getCode())
        );
        // 零点
        String zeroTime = " 00:00:00";
        if (count>0) {
            String today = DateUtil.today() + zeroTime;
            criteria.and("createTime").gte(new DateTime(today, DatePattern.NORM_DATETIME_FORMAT));
        }
        Sort sort = Sort.by(Sort.Order.asc("createTime"));
        List<HistoryData> historyDataList = mongoComponent.selectList(criteria,sort,HistoryData.class);
        HistoryData start = null;
        HistoryData end = null;
        BigDecimal standardVolume = new BigDecimal(standard);
        BigDecimal currentVolume = null;
        handleRowData(deviceId, device, rowDataList, sort, historyDataList, start, end, standardVolume);

        if (rowDataList.size() <= 0){
            return false;
        }
        rowDataList.forEach(data ->{
             int rowDataCount = rowDataMapper.selectCount(new LambdaQueryWrapper<RowData>()
                     .eq(RowData::getDeviceId, deviceId)
                     .eq(RowData::getBeginTime, DateUtil.formatDateTime(data.getBeginTime())));
            if (rowDataCount > 0){
                rowDataMapper.update(data,new LambdaUpdateWrapper<RowData>()
                        .eq(RowData::getDeviceId, deviceId)
                        .eq(RowData::getBeginTime,DateUtil.formatDateTime(data.getBeginTime())));
            } else {
                rowDataMapper.insertRowData(data);
            }
        });
        historyDataList.clear();
        return true;
    }

    private void handleRowData(Integer deviceId, Device device, List<RowData> rowDataList, Sort sort, List<HistoryData> historyDataList, HistoryData start, HistoryData end, BigDecimal standardVolume) {
        BigDecimal currentVolume;
        for (int i = 0; i < historyDataList.size(); i++) {
            HistoryData historyData = historyDataList.get(i);
            currentVolume = new BigDecimal(historyData.getDataValue());
            boolean volumeFlag = standardVolume.compareTo(currentVolume) > 0;
            if (StringUtils.isNull(start) && !volumeFlag) {
                start = historyData;
                continue;
            }
            if (StringUtils.isNull(end)) {
                end = start;
            }
            if (i == historyDataList.size()-1) {
                end = historyData;
            }
            if (StringUtils.isNull(start)){
                continue;
            }
            LocalDateTime startTime = LocalDateTimeUtil.of(end.getCreateTime());
            LocalDateTime startAfterTime = startTime.plusMinutes(20);
            LocalDateTime currentTime = LocalDateTimeUtil.of(historyData.getCreateTime());
            boolean timeFlag = currentTime.isAfter(startAfterTime);
            if (timeFlag || i == historyDataList.size()-1){
                //时间符合超出20分钟结束一列,记录处理当前列数据然后清空
                Criteria startCriteria = new Criteria();
                startCriteria.andOperator(
                        Criteria.where("deviceId").is(deviceId),
                        Criteria.where("dictValue").is(DeviceCommandEnum.CUMULATIVE_VOLUME.getCode()),
                        Criteria.where("createTime").gte(start.getCreateTime())
                );
                List<HistoryData> startData = mongoComponent.selectList(startCriteria, 1, sort,HistoryData.class);
                Criteria endCriteria = new Criteria();
                endCriteria.andOperator(
                        Criteria.where("deviceId").is(deviceId),
                        Criteria.where("dictValue").is(DeviceCommandEnum.CUMULATIVE_VOLUME.getCode()),
                        Criteria.where("createTime").gte(end.getCreateTime())
                );
                List<HistoryData> endData = mongoComponent.selectList(endCriteria, 1, sort,HistoryData.class);
                boolean startDataExists = StringUtils.isNull(startData) || startData.isEmpty();
                boolean endDataExists = StringUtils.isNull(endData) || endData.isEmpty();
                if (startDataExists || endDataExists){
                    continue;
                }
                BigDecimal startBdVolumeData = new BigDecimal(startData.get(0).getDataValue());
                BigDecimal endBdVolumeData = new BigDecimal(endData.get(0).getDataValue());
                BigDecimal result = endBdVolumeData.subtract(startBdVolumeData);
                RowData rowData = new RowData();
                rowData.setDeviceId(deviceId);
                rowData.setDeviceName(device.getDeviceName());
                rowData.setBeginTime(start.getCreateTime());
                rowData.setEndTime(end.getCreateTime());
                rowData.setVolume(String.valueOf(result));
                rowDataList.add(rowData);
                if (!volumeFlag){
                    start = historyData;
                } else {
                    start = null;
                }
                end = null;
                continue;
            }
            if (!volumeFlag){
                end = historyData;
            }
        }
    }

    @Override
    public boolean updateBasisData(Map<String, String> data) {
        List<RowData> rowDataList = rowDataMapper.selectList(new LambdaUpdateWrapper<RowData>());
        for (RowData rowData : rowDataList) {
            if (StringUtils.isNotEmpty(data.get(rowData.getId()+"_coalKind"))){
                rowData.setCoalKind(data.get(rowData.getId()+"_coalKind"));
            }
            if (StringUtils.isNotEmpty(data.get(rowData.getId()+"_weight"))){
                rowData.setWeight(data.get(rowData.getId()+"_weight"));
                BigDecimal volume = new BigDecimal(rowData.getVolume());
                BigDecimal weight = new BigDecimal(rowData.getWeight());
                BigDecimal density = weight.divide(volume,2, RoundingMode.HALF_UP);
                rowData.setDensity(String.valueOf(density));
            }
            if (StringUtils.isNotEmpty(data.get(rowData.getId()+"_moisture"))){
                rowData.setMoisture(data.get(rowData.getId()+"_moisture"));
            }
            if (StringUtils.isNotEmpty(data.get(rowData.getId()+"_grayscale"))){
                rowData.setGrayscale(data.get(rowData.getId()+"_grayscale"));
            }
        }
        return updateBatchById(rowDataList);
    }

    @Override
    public List<RowData> selectAvgDensity() {
        return rowDataMapper.selectAvgDensity();
    }
}
